package com.gitee.qdbp.general.system.biz.personnel.basic;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.ordering.OrderPaging;
import com.gitee.qdbp.able.jdbc.paging.PageList;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.enums.DataState;
import com.gitee.qdbp.base.model.condition.OrderWhere;
import com.gitee.qdbp.base.model.condition.Where;
import com.gitee.qdbp.general.common.api.event.service.IEventTrigger;
import com.gitee.qdbp.general.common.api.sequence.service.ILocalSequenceGenerator;
import com.gitee.qdbp.general.system.api.personnel.basic.IDepartmentCoreBasic;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreBean;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreUpdate;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreWhere;
import com.gitee.qdbp.general.system.biz.personnel.dao.IDepartmentCoreBasicDao;
import com.gitee.qdbp.tools.utils.DateTools;
import com.gitee.qdbp.tools.utils.JsonTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 部门信息基础业务类
 *
 * @author zhh
 * @version 170712
 */
@Service
public class DepartmentCoreBasic implements IDepartmentCoreBasic {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(DepartmentCoreBasic.class);

    /** 序列号生成(ID) **/
    @Autowired
    private ILocalSequenceGenerator sequenceGenerator;

    /** 部门信息DAO **/
    @Autowired
    private IDepartmentCoreBasicDao departmentCoreBasicDao;

    /** 事件触发 **/
    @Autowired(required = false)
    private IEventTrigger eventTrigger;

    /** {@inheritDoc} **/
    @Override
    public DepartmentCoreBean find(DepartmentCoreWhere where) throws ServiceException {
        String msg = "Failed to query DepartmentCore. ";

        if (where == null) {
            log.error(msg + "params is null: where");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (where.getDataState() == null) {
            where.setDataState(DataState.NORMAL);
        }

        doHandleDate(where);

        DepartmentCoreBean bean;
        try {
            bean = departmentCoreBasicDao.find(Where.of(where));
        } catch (Exception e) {
            ServiceException.throwWhenServiceException(e);
            log.error(msg + "\n\t" + JsonTools.toJsonString(where), e);
            throw new ServiceException(ResultCode.DB_SELECT_ERROR, e);
        }

        if (bean == null) {
            log.trace("DepartmentCore not found. {}", JsonTools.toJsonString(where));
        }
        return bean;
    }

    /** {@inheritDoc} **/
    @Override
    public DepartmentCoreBean findById(String id) throws ServiceException {
        String msg = "Failed to query DepartmentCore by id. ";

        if (VerifyTools.isBlank(id)) {
            log.error(msg + "params is null: id");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setId(id);

        return find(where);
    }

    /** {@inheritDoc} **/
    @Override
    public DepartmentCoreBean findByDeptCode(String deptCode) throws ServiceException {
        String msg = "Failed to query DepartmentCore by deptCode. ";

        if (VerifyTools.isBlank(deptCode)) {
            log.error(msg + "params is null: deptCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setDeptCode(deptCode);

        return find(where);
    }

    /** {@inheritDoc} **/
    @Override
    public PageList<DepartmentCoreBean> list(OrderPaging paging) throws ServiceException {
        String msg = "Failed to query DepartmentCore. ";

        if (paging == null) {
            log.error(msg + "params is null: paging");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        return list(new DepartmentCoreWhere(), paging);
    }

    /** {@inheritDoc} **/
    @Override
    public PageList<DepartmentCoreBean> list(DepartmentCoreWhere where, OrderPaging paging) throws ServiceException {
        String msg = "Failed to query DepartmentCore. ";

        if (paging == null) {
            log.error(msg + "params is null: paging");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (where == null) {
            where = new DepartmentCoreWhere();
            where.setDataState(DataState.NORMAL);
        } else if (where.getDataState() == null) {
            where.setDataState(DataState.NORMAL);
        }

        doHandleDate(where);

        try {
            OrderWhere<DepartmentCoreWhere> ow = OrderWhere.of(where, paging.getOrderings());
            return PageList.of(departmentCoreBasicDao.list(ow, paging));
        } catch (Exception e) {
            ServiceException.throwWhenServiceException(e);
            log.error(msg + "\n\t" + JsonTools.toJsonString(where), e);
            throw new ServiceException(ResultCode.DB_SELECT_ERROR, e);
        }
    }

    /** {@inheritDoc} **/
    @Override
    public PageList<DepartmentCoreBean> listByIds(List<String> ids) throws ServiceException {
        String msg = "Failed to query DepartmentCore by id list. ";

        if (VerifyTools.isBlank(ids)) {
            log.error(msg + "params is null: ids");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setIds(ids);

        return list(where, OrderPaging.NONE);
    }

    /** {@inheritDoc} **/
    @Override
    public PageList<DepartmentCoreBean> listByCodes(List<String> deptCodes) throws ServiceException {
        String msg = "Failed to query DepartmentCore by deptCode list. ";

        if (VerifyTools.isBlank(deptCodes)) {
            log.error(msg + "params is null: deptCodes");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setDeptCodes(deptCodes);

        return list(where, OrderPaging.NONE);
    }

    /** {@inheritDoc} **/
    @Override
    public int create(DepartmentCoreBean model) throws ServiceException {
        String msg = "Failed to create DepartmentCore. ";

        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (VerifyTools.isBlank(model.getId())) {
            model.setId(sequenceGenerator.generate(DepartmentCoreBean.TABLE));
        }
        model.setDataState(DataState.NORMAL);

        doHandleDate(model);

        // 向sys_department_core_info表插入记录
        int rows;
        try {
            if (eventTrigger != null) {
                eventTrigger.beforeCreate(DepartmentCoreBean.TABLE, model);
            }
            rows = departmentCoreBasicDao.insert(model);
            if (eventTrigger != null) {
                eventTrigger.afterCreate(DepartmentCoreBean.TABLE, model);
            }
        } catch (DuplicateKeyException e) {
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(model), e);
            throw new ServiceException(ResultCode.DB_DUPLICATE_KEY, e);
        } catch (Exception e) {
            ServiceException.throwWhenServiceException(e);
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(model), e);
            throw new ServiceException(ResultCode.DB_INSERT_ERROR, e);
        }

        if (rows == 0) {
            log.error(msg + "affected rows is 0. \n\t" + JsonTools.toJsonString(model));
            throw new ServiceException(ResultCode.DB_INSERT_ERROR);
        }
        return rows;
    }

    /** {@inheritDoc} **/
    @Override
    public int create(List<DepartmentCoreBean> models) throws ServiceException {
        String msg = "Failed to batch create DepartmentCore. ";

        if (VerifyTools.isBlank(models)) {
            log.error(msg + "params is null: models");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        for (DepartmentCoreBean model : models) {
            if (VerifyTools.isBlank(model.getId())) {
                model.setId(sequenceGenerator.generate(DepartmentCoreBean.TABLE));
            }
            model.setDataState(DataState.NORMAL);

            doHandleDate(model);
        }

        // 向sys_department_core_info表插入记录
        int rows;
        try {
            if (eventTrigger != null) {
                eventTrigger.beforeCreate(DepartmentCoreBean.TABLE, models);
            }
            rows = departmentCoreBasicDao.inserts(models);
            if (eventTrigger != null) {
                eventTrigger.afterCreate(DepartmentCoreBean.TABLE, models);
            }
        } catch (DuplicateKeyException e) {
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(models), e);
            throw new ServiceException(ResultCode.DB_DUPLICATE_KEY, e);
        } catch (Exception e) {
            ServiceException.throwWhenServiceException(e);
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(models), e);
            throw new ServiceException(ResultCode.DB_INSERT_ERROR, e);
        }

        int size = models.size();
        if (rows != size) {
            String desc = size > 0 ? "affected rows " + rows + "!=" + size + ". " : "affected rows is 0. ";
            log.error(msg + desc + "\n\t" + JsonTools.toJsonString(models));
            throw new ServiceException(ResultCode.DB_INSERT_ERROR);
        }
        return rows;
    }

    /** {@inheritDoc} **/
    @Override
    public int update(DepartmentCoreUpdate model, boolean errorOnUnaffected) throws ServiceException {
        String msg = "Failed to update DepartmentCore. ";

        if (model == null) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = model.getWhere(true);
        if (VerifyTools.isBlank(where.getId()) && VerifyTools.isNotBlank(model.getId())) {
            where.setId(model.getId());
        } else if (VerifyTools.isBlank(where.getDeptCode()) && VerifyTools.isNotBlank(model.getDeptCode())) {
            where.setDeptCode(model.getDeptCode());
        }
        model.setDataState(null); // 数据状态只允许通过删除操作来修改
        if (where.getDataState() == null) {
            where.setDataState(DataState.NORMAL);
        }
        return doUpdate(model, 0, errorOnUnaffected);
    }

    /** {@inheritDoc} **/
    @Override
    public int deleteByIds(List<String> ids, boolean errorOnRowsNotMatch) throws ServiceException {
        String msg = "Failed to delete DepartmentCore. ";

        if (VerifyTools.isBlank(ids)) {
            log.error(msg + "params is null: ids");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setIds(ids);

        return doDelete(where, ids.size(), errorOnRowsNotMatch);
    }

    /** {@inheritDoc} **/
    @Override
    public int deleteByCodes(List<String> deptCodes, boolean errorOnRowsNotMatch) throws ServiceException {
        String msg = "Failed to delete DepartmentCore. ";

        if (VerifyTools.isBlank(deptCodes)) {
            log.error(msg + "params is null: deptCodes");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        DepartmentCoreWhere where = new DepartmentCoreWhere();
        where.setDeptCodes(deptCodes);

        return doDelete(where, deptCodes.size(), errorOnRowsNotMatch);
    }

    /** {@inheritDoc} **/
    @Override
    public int delete(DepartmentCoreWhere where, boolean errorOnUnaffected) throws ServiceException {
        String msg = "Failed to delete DepartmentCore. ";

        if (where == null) {
            log.error(msg + "params is null: where");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        return doDelete(where, 0, errorOnUnaffected);
    }

    /**
     * 根据条件删除部门信息
     *
     * @param where 条件
     * @param size 应删除条数, 0表示未知
     * @param errorOnRowsNotMatch 删除行数不匹配时是否抛异常
     * @param isId 是不是唯一主键
     * @return 删除行数
     * @throws ServiceException 删除失败
     */
    private int doDelete(DepartmentCoreWhere where, int size, boolean errorOnRowsNotMatch) throws ServiceException {
        // 逻辑删除
        if (where.getDataState() == null) {
            where.setDataState(DataState.NORMAL);
        }
        DepartmentCoreUpdate model = new DepartmentCoreUpdate();
        model.setDataState(DataState.DELETED);
        model.setWhere(where);
        return doUpdate(model, size, errorOnRowsNotMatch);
    }

    /**
     * 修改部门信息
     *
     * @param model 待修改的内容
     * @param size 应删除条数, 0表示未知
     * @param errorOnRowsNotMatch 删除行数不匹配时是否抛异常
     * @return 受影响行数
     * @throws ServiceException 修改失败
     */
    private int doUpdate(DepartmentCoreUpdate model, int size, boolean errorOnRowsNotMatch) throws ServiceException {
        String msg = "Failed to update DepartmentCore. ";

        if (model == null) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (model.getWhere() == null) {
            log.error(msg + "params is null: model.getWhere()");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        doHandleDate(model);
        doHandleDate(model.getWhere());

        int rows;
        try {
            if (eventTrigger != null) {
                eventTrigger.beforeUpdate(DepartmentCoreBean.TABLE, model);
            }
            rows = departmentCoreBasicDao.update(model);
            if (eventTrigger != null) {
                eventTrigger.afterUpdate(DepartmentCoreBean.TABLE, model);
            }
        } catch (DuplicateKeyException e) {
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(model), e);
            throw new ServiceException(ResultCode.DB_DUPLICATE_KEY, e);
        } catch (Exception e) {
            ServiceException.throwWhenServiceException(e);
            log.error(msg + e.getClass().getSimpleName() + ".\n\t" + JsonTools.toJsonString(model), e);
            throw new ServiceException(ResultCode.DB_UPDATE_ERROR, e);
        }

        if (size > 0 && rows != size || rows == 0) {
            String desc = size > 0 ? "affected rows != " + size + ". " : "affected rows is 0. ";
            if (errorOnRowsNotMatch) {
                log.error(msg + desc + "\n\t" + JsonTools.toJsonString(model));
                throw new ServiceException(ResultCode.DB_UPDATE_ERROR);
            } else {
                log.debug(msg + desc + "\n\t" + JsonTools.toJsonString(model));
            }
        }
        return rows;
    }

    // 由于数据库不支持毫秒, 超过500毫秒会因四舍五入导致变成下一天0点, 因此将毫秒清掉
    protected static void doHandleDate(DepartmentCoreBean model) {
        if (model == null) {
            return;
        }

        if (VerifyTools.isNotBlank(model.getCreateTime())) { // 创建时间
            model.setCreateTime(DateTools.setMillisecond(model.getCreateTime(), 0));
        }
    }

    // 由于数据库不支持毫秒, 超过500毫秒会因四舍五入导致变成下一天0点, 因此将毫秒清掉
    // 处理XxxTime, XxxTimeMin和XxxTimeMax, XxxTimeMinWithDay和XxxTimeMaxWithDay
    protected static void doHandleDate(DepartmentCoreWhere model) {
        if (model == null) {
            return;
        }

        if (VerifyTools.isNotBlank(model.getCreateTime())) { // 创建时间
            model.setCreateTime(DateTools.setMillisecond(model.getCreateTime(), 0));
        }

        if (VerifyTools.isNotBlank(model.getCreateTimeMin())) { // 最小创建时间
            model.setCreateTimeMin(DateTools.setMillisecond(model.getCreateTimeMin(), 0));
        }
        if (VerifyTools.isNotBlank(model.getCreateTimeMinWithDay())) { // 最小创建时间
            model.setCreateTimeMinWithDay(DateTools.toStartTime(model.getCreateTimeMinWithDay()));
        }
        if (VerifyTools.isNotBlank(model.getCreateTimeMax())) { // 最大创建时间
            model.setCreateTimeMax(DateTools.setMillisecond(model.getCreateTimeMax(), 0));
        }
        if (VerifyTools.isNotBlank(model.getCreateTimeMaxWithDay())) { // 最大创建时间
            model.setCreateTimeMaxWithDay(
                DateTools.setMillisecond(DateTools.toEndTime(model.getCreateTimeMaxWithDay()), 0));
        }
    }
}
